# -*- coding: utf-8 -*-

# -- Sheet --

# ### 周学习进度 2021.11.15-11.21
# 
# > 内容：倾斜畸变矫正、分割字符


# ### 1. 先验测试-文档校正


import cv2
import numpy as np
import matplotlib.pyplot as plt

# print(cv2.__version__)

def showImg(src):
    plt.imshow(src)
    plt.axis('off')
    plt.show()

# 文档数据
src = cv2.imread('Img/A4_hello.png')

rows, cols = src.shape[:2]
print(rows,'x', cols)
showImg(src)

# 文档校正—透视变换
def perspective(src, src_pos):
    # 计算边长
    x_dist = np.linalg.norm(src_pos[1] - src_pos[0]).astype(int)
    y_dist = np.linalg.norm(src_pos[2] - src_pos[0]).astype(int)
    print(x_dist, y_dist)
    #计算目标尺寸
    pic_scale = np.array([[0, 0], [x_dist, 0], [0, y_dist], [x_dist, y_dist]])

    # 转换坐标类型
    pos1 = np.float32(src_pos)
    pos2 = np.float32(pic_scale)

    # 获取变换矩阵
    M = cv2.getPerspectiveTransform(pos1, pos2)
    # print(M)

    # 图像透视变换
    # cv2.warpPerspective(src, M， dsize=(cols, rows))
    # src: 原图
    # M： 一个3x3的变换矩阵
    # dsize: 输出图像的尺寸大小, 先指定(第一个参数是)col，再指定(第二个参数是)row
    result = cv2.warpPerspective(src, M, (x_dist, y_dist))

    return result

# 未经过缩放 输出
# 自己标注的目标坐标点
pic_doc = np.array([[45, 180], [220, 85], [60, 290], [270, 185]])  # 需要自己标注给出
target_pic = perspective(src, pic_doc)

# 输出
showImg(target_pic)

# 缩放变换 输出
# 由于透视变换四条边并不一定是平行的，所以透视后的图像大小和真实会有出入，因此需要进行一定比例的缩放
# A4 29.7x21 cm -> 297x210
result2 = cv2.resize(target_pic, (297, 210))

showImg(result2)

# ### 2. 水表表盘校正


# 文档数据
src_meter = cv2.imread('Img/048.png')

rows, cols = src_meter.shape[:2]
print(rows, 'x', cols)
showImg(src_meter)

# 未经过缩放 输出
# 自己标注的目标坐标点
pic_meter = np.array([[100, 145], [155, 212], [80, 160], [135, 228]])  # 需要自己标注给出
target_pic = perspective(src_meter, pic_meter)
showImg(target_pic)
print('before:',target_pic.shape)

# 缩放变换 输出
# 
target_pic = cv2.resize(target_pic, (120, 30))
print(target_pic.shape)
showImg(target_pic)

# 图像切割
from PIL import Image

img = Image.fromarray(target_pic)
showImg(img)

height, width, _ = target_pic.shape
step = width / 5
dpi = target_pic

for i in range(5):
    box = (i * step, 0., (i + 1) * step, height)
    # print(box)
    sub_img = img.crop(box)
    
    print(sub_img.size)
    showImg(sub_img)

# ### 3. 问题
# 
# 1. 拆分后的分辨率问题
# 2. 用OpenCV是否可以自动识别数字框？[分割图像的目标区域](https://blog.csdn.net/sinat_36458870/article/details/78825571)
# 3. 怎么和前序步骤接洽，或者说用什么方式去自动识别水表数字区域
# 4. 整个识别流程分为三步（识别数字区域，语义分割，数字识别），而且各都有失败率，最后组合起来失败率会不会很高


# ### 4. 分享
# 1. 使用 [opencv-python](https://docs.opencv.org/4.x/d6/d00/tutorial_py_root.html) 
# 2. [opencv各模块介绍（2.x）](http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/tutorials.html)
#     1. core： 核心功能模块，包括：基本结构、算法、线性代数、离散傅里叶变换、XML和YML文件I\0等
#     2. imgproc：图像处理模块，包括：滤波、高斯模糊、形态学处理、几何变换、颜色空间转换及直方图计算等
#     3. highgui：高层用户交互模块，包括：GUI、图像与视频I\O等
#     4. ml：机器学习模块，包括：支持向量机、决策树、boosting方法（一种用来提高弱分类器准确度的算法）
#     5. features2d：二维特征检测与描述模块，包括：图像特征检测、描述、匹配等
#     6. video：视频模块，包括：光流法、背景减除、目标跟踪等
#     7. objdetect：目标检测模块，包括：基于Haar特征或HBP特征（local binary patterns）特征的人脸检测、基于HOG（history of oriented gradient ）特征的人体检测
#     8. calib3d：3D模块，包括：摄像机标定、立体匹配、3D重建等
#     9. flann：FLANN（fast library for approximate nearest neighbors）接口模块、FLANN库中包含在高维空间中进行搜索和聚类的方法
#     10. contrib：新贡献的模块，包含一些开发者新贡献出来的尚不成熟的代码
#     11. legacy：遗留模块，包括一些过期的代码，用于保持前后兼容
#     12. gpu：gpu加速模块，包括一些可以利用cuda进行加速的函数
# 
# 3. imgproc-仿射变换（几何变换）
#     1. 一个任意的仿射变换都能表示为 乘以一个矩阵 (线性变换) 接着再 加上一个向量 (平移)，五种操作：平移，翻转，旋转，缩放、错切
#     
#         ![fig1](Img/20180814093713104.png)
# 
#         任何一个仿射变换都可以用一个2x3的矩阵来表示
# 
#         ![](Img/20211121183929.png)
# 
# 4. imgproc-透视变换
#     1. 透视变换是在一个二维图像在三维空间进行变换
#         ![](Img/20211121184044.png)
#         ![](Img/20211121184117.png)
#         ![](Img/20211121184131.png)


